<!DOCTYPE html>
<html lang="en"><head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1"><!-- Begin Jekyll SEO tag v2.8.0 -->
<title>0086: Nodes-n-noodles V - The Drawing Routines | gtkDcoding</title>
<meta name="generator" content="Jekyll v4.3.4" />
<meta property="og:title" content="0086: Nodes-n-noodles V - The Drawing Routines" />
<meta name="author" content="Ron Tarrant" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="This GTK Tutorial covers drawing routines for a node-n-noodles demo." />
<meta property="og:description" content="This GTK Tutorial covers drawing routines for a node-n-noodles demo." />
<link rel="canonical" href="http://localhost:4000/posts/0086-nodes-v-node-drawing-routines.html" />
<meta property="og:url" content="http://localhost:4000/posts/0086-nodes-v-node-drawing-routines.html" />
<meta property="og:site_name" content="gtkDcoding" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-11-08T00:00:00-05:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="0086: Nodes-n-noodles V - The Drawing Routines" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"Ron Tarrant"},"dateModified":"2019-11-08T00:00:00-05:00","datePublished":"2019-11-08T00:00:00-05:00","description":"This GTK Tutorial covers drawing routines for a node-n-noodles demo.","headline":"0086: Nodes-n-noodles V - The Drawing Routines","mainEntityOfPage":{"@type":"WebPage","@id":"http://localhost:4000/posts/0086-nodes-v-node-drawing-routines.html"},"url":"http://localhost:4000/posts/0086-nodes-v-node-drawing-routines.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="stylesheet" href="../assets/main.css">
  <link rel="stylesheet" href="../css/style.css" /><link type="application/atom+xml" rel="alternate" href="http://localhost:4000/feed.xml" title="gtkDcoding" /></head>
<body><header class="site-header" role="banner">

  <div class="wrapper"><a class="site-title" rel="author" href="../">gtkDcoding</a><nav class="site-nav">
        <input type="checkbox" id="nav-trigger" class="nav-trigger" />
        <label for="nav-trigger">
          <span class="menu-icon">
            <svg viewBox="0 0 18 15" width="18px" height="15px">
              <path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"/>
            </svg>
          </span>
        </label>

        <div class="trigger"><a class="page-link" href="../about.html">About</a><a class="page-link" href="../index-reverse.html">Posts in Date Order</a><a class="page-link" href="../topics.html">Blog Posts by Topic</a></div>
      </nav></div>
</header>
<main class="page-content" aria-label="Content">
      <div class="wrapper">
        <article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
	<header class="post-header">
		<link rel="stylesheet" href="../css/font_size.css" />
		<link rel="stylesheet" href="../css/figure.css" />
		<link rel="stylesheet" href="../css/topics/nodes.css" />  <!-- sub in the tag/topic -->
		<link rel="stylesheet" href="../css/modal.css" />
		<link rel="stylesheet" href="../css/post.css" />
		<link rel="stylesheet" href="../css/mascot_effects.css" />

		
		
		<p class="post-meta">
		<time class="dt-published" datetime="2019-11-08T00:00:00-05:00" itemprop="datePublished">Friday, November 8, 2019
		</time>• by <span itemprop="author" itemscope itemtype="http://schema.org/Person"><span class="p-author h-card" itemprop="name">Ron Tarrant</span></span></p>
	</header>

	<div class="post-content e-content" itemprop="articleBody">
		<div class="skew-line"></div>
		<h1 id="0086-nodes-n-noodles-v--the-drawing-routines">0086: Nodes-n-noodles V – The Drawing Routines</h1>

<p>Before digging into the details of drawing the node, let’s do a quick summary of what we’re up to with the <code class="language-plaintext highlighter-rouge">MoveableNode</code>. Here’s a visual of what we’re aiming for (in case you weren’t here last time):</p>

<!-- 0, 1 -->
<!-- first occurrence of application and terminal screen shots on a single page -->
<div class="screenshot-frame">
	<div class="frame-header">
		Results of this example:
	</div>
	<div class="frame-screenshot">
		<figure>
			<img id="img0" src="../images/screenshots/023_nodes/nodes_06.png" alt="Current example output" />		<!-- img# -->
			
			<!-- Modal for screenshot -->
			<div id="modal0" class="modal">																	<!-- modal# -->
				<span class="close0">&times;</span>															<!-- close# -->
				<img class="modal-content" id="img00" />															<!-- img## -->
				<div id="caption"></div>
			</div>
			
			<script>
			// Get the modal
			var modal = document.getElementById("modal0");														// modal#
			
			// Get the image and insert it inside the modal - use its "alt" text as a caption
			var img = document.getElementById("img0");															// img#
			var modalImg = document.getElementById("img00");													// img##
			var captionText = document.getElementById("caption");

			img.onclick = function()
			{
			  modal.style.display = "block";
			  modalImg.src = this.src;
			  captionText.innerHTML = this.alt;
			}
			
			// Get the <span> element that closes the modal
			var span = document.getElementsByClassName("close0")[0];											// close#
			
			// When the user clicks on <span> (x), close the modal
			span.onclick = function()
			{ 
				modal.style.display = "none";
			}
			</script>
			<figcaption>
			Current example output
			</figcaption>
		</figure>
	</div>

	<div class="frame-terminal">
		<figure class="right">
			<img id="img1" src="../images/screenshots/023_nodes/nodes_06_term.png" alt="Current example terminal output" />		<!-- img#, filename -->

			<!-- Modal for terminal shot -->
			<div id="modal1" class="modal">																				<!-- modal# -->
				<span class="close1">&times;</span>																		<!-- close# -->
				<img class="modal-content" id="img11" />																		<!-- img## -->
				<div id="caption"></div>
			</div>
			
			<script>
			// Get the modal
			var modal = document.getElementById("modal1");																	// modal#
			
			// Get the image and insert it inside the modal - use its "alt" text as a caption
			var img = document.getElementById("img1");																		// img#
			var modalImg = document.getElementById("img11");																// img##
			var captionText = document.getElementById("caption");

			img.onclick = function()
			{
			  modal.style.display = "block";
			  modalImg.src = this.src;
			  captionText.innerHTML = this.alt;
			}
			
			// Get the <span> element that closes the modal
			var span = document.getElementsByClassName("close1")[0];														// close#
			
			// When the user clicks on <span> (x), close the modal
			span.onclick = function()
			{ 
				modal.style.display = "none";
			}
			</script>

			<figcaption>
				Current example terminal output (click for enlarged view)
			</figcaption>
		</figure>
	</div>

	<div class="frame-footer">																								<!-- ------------- filename (below) --------- -->
		The code file for this example is available <a href="https://github.com/rontarrant/gtkd_demos/blob/master/023_nodes/nodes_06_draw_node_drawingarea.d" target="_blank">here</a>.
	</div>
</div>
<!-- end of snippet for first (1st) occurrence of application and terminal screen shots on a single page -->

<p><em>Note: You’ll notice that the above link doesn’t lead to the same source file we used last time. That code used an external image whereas this one has the drawing routines mentioned above.</em></p>

<p>So, here’s a summary of what we’re doing…</p>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">MoveableNode</code> is based on a the <code class="language-plaintext highlighter-rouge">DrawingArea</code> widget.
    <ul>
      <li>It’s the parent object, and</li>
      <li>it has no drawing routines of its own.</li>
      <li>This parent object’s properties determine the overall size of the <code class="language-plaintext highlighter-rouge">MoveableNode</code>.</li>
    </ul>
  </li>
  <li>The Shapes—the circles and rounded rectangles that make up the <code class="language-plaintext highlighter-rouge">MoveableNode</code>—are child objects.
    <ul>
      <li>Each shape has its own drawing routine, and</li>
      <li>does its own preparatory calculations for shape, size, and color.</li>
      <li>Each shape also keeps track of its location within the <code class="language-plaintext highlighter-rouge">DrawingArea</code> that is the <code class="language-plaintext highlighter-rouge">MoveableNode</code>.</li>
      <li>Shapes are drawn in z-depth order so, for instance, the circles used as terminals aren’t masked by the larger shape of the <code class="language-plaintext highlighter-rouge">MoveableNode</code> itself.</li>
    </ul>
  </li>
</ul>

<p>And the reason it’s done like this is so that when we get around to moving this <code class="language-plaintext highlighter-rouge">MoveableNode</code> object, all its decorations and details come along for the ride without any extra work on our part.</p>

<p>Okay, that’s out of the way. Let’s get at it…</p>

<h2 id="the-moveablenode-class">The MoveableNode Class</h2>

<p>Compared to our first <code class="language-plaintext highlighter-rouge">MoveableNode</code> with its external image, this one is a bit more crowded. An <code class="language-plaintext highlighter-rouge">Image</code> is far less code, but it’s also external and, therefore, less portable, so in moving toward a more self-contained approach, here’s where we stand:</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="n">MoveableNode</span> <span class="p">:</span> <span class="n">DrawingArea</span>
<span class="p">{</span>
	<span class="n">NodeShape</span> <span class="n">nodeShape</span><span class="p">;</span> <span class="c1">// appearance of the node</span>
	<span class="n">NodeHandle</span> <span class="n">nodeHandle</span><span class="p">;</span> <span class="c1">// appearance of the drag handle</span>
	<span class="n">NodeTerminalIn</span> <span class="n">nodeTerminalIn</span><span class="p">;</span> <span class="c1">// appearance of the input terminal</span>
	<span class="n">TerminalInStatus</span> <span class="n">terminalInStatus</span><span class="p">;</span> <span class="c1">// appearance of the input terminal's status block</span>
	<span class="n">NodeTerminalOut</span> <span class="n">nodeTerminalOut</span><span class="p">;</span> <span class="c1">// appearance of the output terminal</span>
	<span class="n">TerminalOutStatus</span> <span class="n">terminalOutStatus</span><span class="p">;</span> <span class="c1">// appearance of the output terminal's status block</span>
	<span class="kt">int</span> <span class="n">width</span> <span class="p">=</span> <span class="mi">113</span><span class="p">,</span> <span class="n">height</span> <span class="p">=</span> <span class="mi">102</span><span class="p">;</span>
</code></pre></div></div>

<p>Here in the preamble, we declare all those shapes I mentioned. What we’re going to end up with is in the screen shot above. Please note that there are six sub-shapes that make up the <code class="language-plaintext highlighter-rouge">MoveableNode</code> and each is an object.</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	<span class="k">this</span><span class="p">()</span>
	<span class="p">{</span>
		<span class="n">nodeShape</span> <span class="p">=</span> <span class="k">new</span> <span class="n">NodeShape</span><span class="p">();</span>
		<span class="n">nodeTerminalIn</span> <span class="p">=</span> <span class="k">new</span> <span class="n">NodeTerminalIn</span><span class="p">();</span>
		<span class="n">terminalInStatus</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TerminalInStatus</span><span class="p">();</span>
		<span class="n">nodeTerminalOut</span> <span class="p">=</span> <span class="k">new</span> <span class="n">NodeTerminalOut</span><span class="p">();</span>
		<span class="n">terminalOutStatus</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TerminalOutStatus</span><span class="p">();</span>
		<span class="n">nodeHandle</span> <span class="p">=</span> <span class="k">new</span> <span class="n">NodeHandle</span><span class="p">();</span>
		<span class="n">addOnDraw</span><span class="p">(&amp;</span><span class="n">onDraw</span><span class="p">);</span>
		
	<span class="p">}</span> <span class="c1">// this()</span>
</code></pre></div></div>

<p>In the constructor, each of the sub-shapes is instantiated and the <code class="language-plaintext highlighter-rouge">onDraw()</code> callback is hooked up.</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	<span class="kt">bool</span> <span class="n">onDraw</span><span class="p">(</span><span class="n">Scoped</span><span class="p">!</span><span class="n">Context</span> <span class="n">context</span><span class="p">,</span> <span class="n">Widget</span> <span class="n">w</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">setSizeRequest</span><span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">);</span> <span class="c1">// without this, nothing shows</span>

		<span class="c1">// call sub-objects' draw routines?</span>
		<span class="n">nodeShape</span><span class="p">.</span><span class="n">draw</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
		<span class="n">nodeTerminalIn</span><span class="p">.</span><span class="n">draw</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
		<span class="n">nodeTerminalOut</span><span class="p">.</span><span class="n">draw</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
		<span class="n">nodeHandle</span><span class="p">.</span><span class="n">draw</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
		<span class="n">terminalInStatus</span><span class="p">.</span><span class="n">draw</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
		<span class="n">terminalOutStatus</span><span class="p">.</span><span class="n">draw</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
		
		<span class="k">return</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
		
	<span class="p">}</span> <span class="c1">// onDraw()</span>

<span class="p">}</span> <span class="c1">// class MoveableNode</span>
</code></pre></div></div>

<p>And, naturally, in the <code class="language-plaintext highlighter-rouge">onDraw()</code> callback, the drawing routines are called. As mentioned, these routines are encapsulated in their respective classes/objects, so at this point, we don’t need to concern ourselves with them any more than we have.</p>

<p>And I’d like to point out that the <code class="language-plaintext highlighter-rouge">terminalStatus</code> shapes are based on the <code class="language-plaintext highlighter-rouge">nodeHandle</code> shape which is derived from the <code class="language-plaintext highlighter-rouge">nodeShape</code>, so a lot of this code is being reused… sort of. In the interests of full-blown inheritance, I could have created one parent class for a general rectangular shape with rounded corners and then derived all the rest from it. But for clarity, there is some repetition. I mean, it’s not like we have to be careful how much RAM we use, right? So, let’s just set our metaphorical elbows akimbo and get on with life.</p>

<p>I did go so far as to outline two classes for a generic <code class="language-plaintext highlighter-rouge">NodeTerminal</code> shape and a generic <code class="language-plaintext highlighter-rouge">TerminalStatus</code> shape and from there, derived the <code class="language-plaintext highlighter-rouge">-In</code> and <code class="language-plaintext highlighter-rouge">-Out</code> versions of both. But that’s as far as I went with it. If you’re up for a bit of fun, you might take it upon yourself to design a master shape class and derive all the rounded rectangle shapes from it.</p>

<h3 id="the-sub-shapes">The Sub-shapes</h3>

<p>Each of the sub-shapes keeps track of:</p>

<ul>
  <li>rim and fill colors, and</li>
  <li>it’s offset from the <code class="language-plaintext highlighter-rouge">MoveableNode</code> origin.</li>
</ul>

<p>Drawing routines are in the sub-shape… unless the sub-shape is derived from a parent shape. In those cases (specifically, the <code class="language-plaintext highlighter-rouge">NodeTerminalIn</code>/<code class="language-plaintext highlighter-rouge">Out</code> and <code class="language-plaintext highlighter-rouge">TerminalStatusIn</code>/<code class="language-plaintext highlighter-rouge">Out</code>) drawing routines are in the parent classes <code class="language-plaintext highlighter-rouge">NodeTerminal</code> and <code class="language-plaintext highlighter-rouge">TerminalStatus</code>.</p>

<p>Have a gander at the sub-shape classes to see what I mean. Here’s the <code class="language-plaintext highlighter-rouge">NodeTerminalIn</code> class and its parent/root class, the <code class="language-plaintext highlighter-rouge">NodeTerminal</code>:</p>

<pre><code class="language-declare">class NodeTerminalIn : NodeTerminal
{
	double[] _rimRGBA = [0.129, 0.243, 0.608, 1.0];
	double[] _fillRGBA = [1.0, 0.706, 0.004, 1.0];
	int _xOffset = 6, _yOffset = 34;
	
	this()
	{
		super(_xOffset, _yOffset, _fillRGBA, _rimRGBA);
		
	} // this()
	
} // class NodeTerminalIn


class NodeTerminal
{
	double _radius = 5,
			 _lineWidth = 2;
	int _xOffset, _yOffset;
	double[] _fillRGBA, _rimRGBA;
	
	this(int xOffset, int yOffset, double[] fillRGBA, double[] rimRGBA)
	{
		_xOffset = xOffset;
		_yOffset = yOffset;
		_fillRGBA = fillRGBA;
		_rimRGBA = rimRGBA;
		
	} // this()
	
	
	void draw(Context context)
	{
		// set up the path and color
		context.newSubPath();
		context.arc(_xOffset, _yOffset, _radius, 0, PI * 2);
		context.closePath();
		
		// fill the circle
		context.setSourceRgba(_fillRGBA[0], _fillRGBA[1], _fillRGBA[2], _fillRGBA[3]);
		context.fillPreserve();
		
		// color the path
		context.setSourceRgba(_rimRGBA[0], _rimRGBA[1], _rimRGBA[2], _rimRGBA[3]);
		context.setLineWidth(_lineWidth);
		context.stroke();
		
	} // draw()
	
} // class NodeTerminal

</code></pre>

<p>By and large, each class breaks down the same way. The preamble has:</p>

<ul>
  <li>the origin of the shape as an offset from the origin of the parent class/object, <code class="language-plaintext highlighter-rouge">MoveableNode</code>,</li>
  <li>the sub-shape’s dimensions along with the radius, and</li>
  <li>colors, line width, etc.</li>
</ul>

<p>Because a circle (i.e. a <code class="language-plaintext highlighter-rouge">NodeTerminal</code>) only needs a point of origin and a radius in order to draw itself, there is one set of variables that aren’t used here. They only show up in the rectangular shapes (<code class="language-plaintext highlighter-rouge">NodeShape</code>, <code class="language-plaintext highlighter-rouge">NodeHandle</code>, and <code class="language-plaintext highlighter-rouge">TerminalStatus</code>):</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">double</span><span class="p">[]</span> <span class="n">northEastArc</span><span class="p">,</span> <span class="n">southEastArc</span><span class="p">,</span> <span class="n">southWestArc</span><span class="p">,</span> <span class="n">northWestArc</span><span class="p">;</span>
</code></pre></div></div>

<p>These four 2-element arrays keep track of where to begin and end drawing each of the rectangle’s rounded corners.</p>

<p>The constructors for the sub-shapes are all about doing prep work for the drawing routines and the <code class="language-plaintext highlighter-rouge">draw()</code> function carries out the actual drawing. And I should point out that if these classes/objects were standalone, each <code class="language-plaintext highlighter-rouge">draw()</code> function would become an <code class="language-plaintext highlighter-rouge">onDraw()</code> callback hooked up to the <code class="language-plaintext highlighter-rouge">onDraw</code> signal for each object. But because of how we’re doing this—calling all the <code class="language-plaintext highlighter-rouge">draw()</code> functions from the <code class="language-plaintext highlighter-rouge">MoveableNode.onDraw()</code> parent callback—we don’t need to hook up the signals for these shapes. In fact, there are no signals at this level to hook them up to, anyway.</p>

<p>Everything else is very much like what we covered in earlier posts for <em>Cairo</em> drawing. The only difference, really, is that we pass the <code class="language-plaintext highlighter-rouge">MoveableNode</code>’s drawing <code class="language-plaintext highlighter-rouge">Context</code> to each sub-shape’s <code class="language-plaintext highlighter-rouge">draw()</code> function.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Full disclosure: I didn’t start with the image of the node and develop the drawing routines from it. I started with a hand-drawn node, went to an <em>Inkscape</em> drawing, then developed the drawing routines. Once I got the kinks ironed out and the code was working, I did a screen shot and created the image file from there. So, in fact, I put the cart before the horse. (Don’t tell anyone.)</p>

<p>Next time, we’ll get into hotspots. See you then.</p>

<div class="blog-nav">
	<div style="float: left;">
		<a href="./0085-nodes-iv-node-drawing.html">Previous: Node IV -Drawing Routines</a>
	</div>
	<div style="float: right;">
		<a href="./0087-nodes-vi-hotspots.html">Next: Nodes VI - Hot Spots</a>
	</div>
</div>
<p>
	<h3></h3>
<div class="inpage-frame">
	<a href="https://github.com/sponsors/rontarrant">
		<BR>
		<BR>
		<B>Is this article useful? Educational? Entertaining, perhaps?</B>
		<BR>
		<figure class="left">
			<img src="../images/favorite_32.png" alt="Sponsorship heart" style="width: 32px; height: 32px;">
		</figure>
		You're free to accept or decline this invitation to become our newest sponsor.
	</a>
</div>
	<h4 class="comment-blurb"><B>Comments? Questions? Observations?</B></h4>
	<p>
		Did we miss a tidbit of information that would make this post even more informative? Let's talk about it in the comments.
	</p>
	<script src="https://utteranc.es/client.js"
		repo="rontarrant"
		issue-term="pathname"
		theme="github-light"
		crossorigin="anonymous"
		async>
	</script>
	<ul>
		<li> come on over to the <a href="https://forum.dlang.org/">D Language Forum</a> and look for one of the <i>gtkDcoding</i> announcement posts, </li>
		<li> drop by <a href="https://forum.gtkd.org/">the <i>GtkD Forum</i></a>,</li>
		<li> follow the link below to email me, or</li>
		<li> go to the	<a href="https://www.facebook.com">gtkDcoding Facebook page.</a></li>
	</ul>
</p>
<p> You can also subscribe <a href="/feed.xml">via RSS</a> so you won't miss anything. Thank you very much for dropping by.</p>
<p>&copy; Copyright 2025 Ron Tarrant </p>
</div>

	<a class="u-url" href="./0086-nodes-v-node-drawing-routines.html" hidden></a>
</article>

      </div>
    </main><footer class="site-footer h-card">
  <data class="u-url" href="/"></data>

  <div class="wrapper">

    <h2 class="footer-heading">gtkDcoding</h2>

    <div class="footer-col-wrapper">
      <div class="footer-col footer-col-1">
        <ul class="contact-list">
          <li class="p-name">Ron Tarrant</li><li><a class="u-email" href="mailto:gtkDcoding@gmail.com">gtkDcoding@gmail.com</a></li></ul>
      </div>

      <div class="footer-col footer-col-2"><ul class="social-media-list"><li><a href="https://github.com/rontarrant"><svg class="svg-icon"><use xlink:href="../assets/minima-social-icons.svg#github"></use></svg> <span class="username">rontarrant</span></a></li></ul>
</div>

      <div class="footer-col footer-col-3">
        <p>Simple examples of how to use GtkD to build GUI applications.</p>
      </div>
    </div>

  </div>

</footer>
</body>

</html>
